home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / bipl.zip / PROGS.ZIP / FORMAT.ICN < prev    next >
Text File  |  1992-09-28  |  5KB  |  159 lines

  1. ############################################################################
  2. #
  3. #    File:     format.icn
  4. #
  5. #    Subject:  Program to word wrap a range of text
  6. #
  7. #    Author:   Robert J. Alexander
  8. #
  9. #    Date:     September 18, 1990
  10. #
  11. ###########################################################################
  12. #
  13. #  Filter to word wrap a range of text.
  14. #
  15. #  A number of options are available, including full  justification (see
  16. #  usage text,  below).  All lines that have the same indentation as the
  17. #  first  line (or same  comment leading character format if  -c option)
  18. #  are wrapped.  Other lines are left as is.
  19. #
  20. #  This  program  is useful in conjunction with editors  that can invoke
  21. #  filters on a range of selected text.
  22. #
  23. #  The -c option attemps to establish the form of a comment based on the
  24. #  first  line, then does its best to deal  properly  with the following
  25. #  lines.   The  types of  comment lines that  are handled  are those in
  26. #  which  each  line starts with a "comment" character string  (possibly
  27. #  preceded  by  spaces).  While formatting  comment  lines, text  lines
  28. #  following the prototype line that don't match the  prototype  but are
  29. #  flush with  the  left margin are also  formatted  as  comments.  This
  30. #  feature simplifies  initially entering  lengthy  comments  or  making
  31. #  major modifications, since  new  text can  be entered without concern
  32. #  for comment formatting, which will be done automatically later.
  33. #
  34. ############################################################################
  35. #
  36. #  Links: options
  37. #
  38. ############################################################################
  39.  
  40. link options
  41.  
  42. procedure main(arg)
  43.    local usage, opts, tabs, comment, format, just1, space, nspace, wchar, Entab
  44.    local line, pre, empty, outline, spaces, word, len, width, xspace, Detab
  45.    local outpre
  46.    #
  47.    #  Process the options.
  48.    #
  49.    usage := 
  50.      "usage: format [-options]\n_
  51.             \t-w N\tspecify line width (default 72)\n_
  52.             \t-t N\tspecify tab width (default 8)\n_
  53.             \t-j\tfully justify lines\n_
  54.             \t-J\tfully justify last line, too\n_
  55.             \t-c\tattempt to format program comments\n_
  56.             \t-n\tdon't put extra spaces after sentences\n_
  57.             \t-h\tprint help message"
  58.    opts := options(arg,"ht+w+cjJn")
  59.    if \opts["h"] then stop(usage)
  60.    width := integer(\opts["w"]) | 72
  61.    tabs := (integer(\opts["t"]) | 8) + 1
  62.    if tabs >= 2 then {
  63.       Detab := detab
  64.       Entab := entab
  65.       }
  66.    else Entab := Detab := 1
  67.    comment := opts["c"]
  68.    format := if \just1 | \opts["j"] then justify else 1
  69.    just1 := opts["J"]
  70.    xspace := if \opts["s"] then '' else '.?:!'
  71.    #
  72.    #  Initialize variables.
  73.    #
  74.    space := ' \t'
  75.    nspace := ~space
  76.    wchar := nspace
  77.    #
  78.    #  Read the first line to establish a prototype of comment format
  79.    #  if -c option, or of leading spaces if normal formatting.
  80.    #
  81.    line := Detab(read(),tabs) | exit()
  82.    line ?
  83.       pre := (tab(many(space)) | "") ||
  84.      if \comment then
  85.         tab(many(nspace)) || tab(many(space)) |
  86.             stop("### Can't establish comment pattern")
  87.      else
  88.         ""
  89.    width -:= *pre
  90.    empty := trim(pre)
  91.    outpre := Entab(pre,tabs)
  92.    outline := spaces := ""
  93.    repeat {
  94.       line ? {
  95.      #
  96.      #  If this line indicates a formatting break...
  97.      #
  98.      if (=empty & pos(0)) | (=pre & any(space) | pos(0)) |
  99.             (/comment & not match(pre)) then {
  100.         write(outpre,"" ~== outline)
  101.         outline := spaces := ""
  102.         write(line)
  103.         }
  104.      #
  105.      #  Otherwise continue formatting.
  106.      #
  107.      else {
  108.         =pre
  109.         tab(0) ? {
  110.            tab(many(space))
  111.            while word := tab(many(wchar)) & (tab(many(space)) | "") do {
  112.           if *outline + *spaces + *word > width then {
  113.              write(outpre,"" ~== format(outline,width))
  114.              outline := spaces := ""
  115.              }
  116.           outline ||:= spaces || word
  117.           spaces := if any(xspace,word[-1]) then "  " else " "
  118.           }
  119.            }
  120.         }
  121.      }
  122.       line := Detab(read(),tabs) | break
  123.       }
  124.    write(outpre,"" ~== (if \just1 then justify else 1)(outline,width))
  125. end
  126.  
  127.  
  128. #
  129. #  justify(s,width) -- Inserts extra spaces between words of "s" so that
  130. #  "s" will  be exactly  "width" characters  long.   "s" is  trimmed  of
  131. #  spaces  on the right  and left ends.  If  "s" contains fewer than two
  132. #  words, or if the trimmed version is longer than "width", the  trimmed
  133. #  version  of "s" is returned unchanged.  Where some gaps between words
  134. #  are  required  to  be   wider  than  others,  the  extra  spaces  are
  135. #  distributed randomly to minimize "rivering" in justified paragraphs.
  136. #
  137. procedure justify(s,width)
  138.    local wlist,wset,t,r
  139.    static space,nspace
  140.    initial {
  141.       space := ' '
  142.       nspace := &cset -- space
  143.       }
  144.    s := trim(s[many(space,s) | 1:0])
  145.    wlist := []
  146.    s ? while put(wlist,[tab(many(nspace)),*tab(many(space)) | 0])
  147.    if *s >= width | *wlist < 2 then return s
  148.    wset := set(wlist[1:-1])
  149.    t := (width - *s) / *wset
  150.    every (!wset)[2] +:= t
  151.    every 1 to (width - *s) % *wset do {
  152.       (t := ?wset)[2] +:= 1
  153.       delete(wset,t)
  154.       }
  155.    r := ""
  156.    every t := !wlist do r ||:= t[1] || repl(" ",t[2])
  157.    return r
  158. end
  159.